import { chromium, Browser, Page } from 'playwright';
import fs from 'fs'
import * as _ from 'lodash'
import ejs from 'ejs'
require('dotenv').config();

// 发送邮件
import nodemailer from 'nodemailer'
import dayjs from 'dayjs';


// 果仁网账号
const GR_ACCOUNT = process.env.GR_ACCOUNT || '';
const GR_PWD = process.env.GR_PWD || '';
const DAY_FORMAT = 'YYYY-MM-DD'

type TStock = {
  stock_name: string;
  stock_code: string;
  stock_price: number;
  // 本期建议卖出
  will_sell?: boolean;
  // 本期建议买入
  will_buy?: boolean;
  sort?: number;
};


// 根据日期选股
const select_stock = async (date: string | null) => {
  if(date === null){
    return []
  }
  // headless:false, 能在前台看到浏览器, --start-maxmized，浏览器全屏
  const browser: Browser = await chromium.launch({ headless: false, args: ['--start-maximized'] });
  // viewport:null, 设置全屏
  const context = await browser.newContext({ viewport: null })
  const page: Page = await context.newPage();

  await page.goto('https://guorn.com/stock');
  // 找到右上角的登录按钮, 点击, 显示出登录弹框
  await page.locator('a:has-text("登录")').click();
  const accountInput = await page.$('#login-Id');
  // 输入果仁网账号
  await accountInput?.type(GR_ACCOUNT);
  // await browser.close();
  const pwdInput = await page.$('#login-password');
  // 输入果仁网密码
  await pwdInput?.type(GR_PWD);
  // 点击登录按钮
  const submitButton = await page.$('#sign-in');
  await submitButton?.click();

  // 设定小市值条
  // 去掉创业版
  await page.locator('div').filter({ hasText: /^上市板块：全部$/ }).getByRole('button').click();
  await page.locator('div').filter({ hasText: /^创业板$/ }).locator('div').click();
  await page.locator('#popupMask').click();
  // 排除ST
  await page.locator('.row1 > div:nth-child(5) > .btn').click();
  await page.locator('#popupMask').click();
  await page.locator('#stockScreen-range').getByRole('combobox').nth(3).selectOption('1');

  // 总市值放入筛选条件
  await page.getByPlaceholder('搜索财务选项与指标').click();
  await page.getByPlaceholder('搜索财务选项与指标').fill('总市值');
  await page.getByText('行情--股本和市值--总市值').click();
  // 5日平均成交额放入筛选条件
  await page.getByPlaceholder('搜索财务选项与指标').click();
  await page.getByPlaceholder('搜索财务选项与指标').fill('5日平均');
  await page.getByText('行情--成交额--5日平均成交额').click();
  // 市盈率放入筛选条件
  await page.getByPlaceholder('搜索财务选项与指标').click();
  await page.getByPlaceholder('搜索财务选项与指标').click({});
  await page.getByPlaceholder('搜索财务选项与指标').fill('市盈率');
  await page.getByText('财务指标--估值--市盈率', { exact: true }).click();
  // 设定三个筛选条件的值
  await page.getByText('筛选条件3').click();


  const filterDiv = page.locator('div#stockScreen-filter');
  const condition_items = filterDiv.locator('.filter-cnt').locator('.condition-item');
  // 第一个条件
  const firstConditionItem = condition_items.nth(0);
  const firstOperater = firstConditionItem.locator('.operator');
  const firstSelect = firstOperater.locator('.form-control');
  // 点击第一个筛选条件的操作符
  await firstSelect.waitFor();
  await firstSelect.click();
  // 选择排名最小的50个
  await firstSelect.selectOption({ label: '排名最小' });
  await firstConditionItem.locator('.values input').first().fill('50')

  // 点击第二个条件设为大于 0.1
  const _2ConditionItem = condition_items.nth(1);
  await _2ConditionItem.locator('.values input').first().fill('0.1')


  // 第三个条件
  const _3ConditionItem = condition_items.nth(2);
  const _3Operater = _3ConditionItem.locator('.operator');
  const _3Select = _3Operater.locator('.form-control');
  await _3Select.waitFor();
  await _3Select.click();
  await _3Select.selectOption({ label: '大于' });
  await _3ConditionItem.locator('.values input').first().fill('0.1')

  // 选择排名条件 市净率
  await page.getByText('排名条件', { exact: true }).click();
  await page.getByText('排名条件', { exact: true }).click();
  await page.getByPlaceholder('搜索财务选项与指标').click();
  await page.getByPlaceholder('搜索财务选项与指标').fill('市净率');
  await page.getByText('财务指标--估值--市净率', { exact: true }).click();
  // 排名条件中加入收盘价
  await page.getByPlaceholder('搜索财务选项与指标').click();
  await page.getByPlaceholder('搜索财务选项与指标').fill('收盘价');
  await page.getByText('行情--股票价格--收盘价').click();

  await page.locator('div').filter({ hasText: /^2收盘价从小到大从大到小全部一级行业内二级行业内$/ }).getByPlaceholder('1').click();
  await page.locator('div').filter({ hasText: /^2收盘价从小到大从大到小全部一级行业内二级行业内$/ }).getByPlaceholder('1').fill('2');


  // 点击每日选股
  await page.getByText('每日选股').click();
  // 输入选股日期
  const dateInput = await page.$('div.input-group.date.form_date input.form-control');
  //
  dateInput?.fill(date);
  //点击开始选股
  await page.getByRole('button', { name: '开始选股' }).click();


  //从这个div下方获取数据，div#screen-grid , .main , .body
  // name="r0"  .td name=0 .name， 是股票名称，   .link ，是股票代码 
  // .td name=4， 收盘价 
  await page.waitForSelector('div.tt');
  const tt = await page.$('div.tt');

  await tt?.waitForSelector('div[name="r0"]');
  // name = r0是第一行, 循环得到前10行的数据;
  const stock_arr = [];

  for (let i = 0; i < 10; i++) {
    // const selectStr = `div[name="r${i}"]`
    const row_data = await tt?.$(`div[name="r${i}"]`);
    // 获取编号
    const sortDiv = await row_data?.$('div:first-child');
    const sort = await sortDiv?.innerText();
    // 获取股票名称
    const stock_div = await row_data?.$('.td[name="0"]');
    const stock_name_div = await stock_div?.$('.name');
    const stock_name = await stock_name_div?.innerText();
    // 获取股票代码
    const stock_code_element = await stock_div?.$('.link');
    const stock_code = await stock_code_element?.innerText();
    // 获取股票收盘价
    const stock_price_div = await row_data?.$('.td[name="4"]');
    const stock_price = await stock_price_div?.innerText();

    stock_arr.push({
      sort: sort ? parseInt(sort) : 0,
      stock_name: stock_name || '',
      stock_code: stock_code || '',
      stock_price: stock_price ? parseFloat(stock_price) : 0
    })
  }

  // await page.waitForTimeout(4000)
  await page.close();
  return stock_arr;
}

const writeSelect2File = async (date: string, res: any[]) => {
  // console.log(__dirname)
  const dir = __dirname + '/select_res/';
  const file_dir = dir + `${date}.json`;
  fs.writeFileSync(file_dir, JSON.stringify(res), 'utf-8');
}

const readFileByDate = async (date: string) => {
  const dir = __dirname + '/select_res/';
  const file_dir = dir + `${date}.json`;
  const data = fs.readFileSync(file_dir, 'utf-8');
  return JSON.parse(data);
}

const stockChanges = async (prev_stocks: TStock[], current_stocks: TStock[]) => {
  // 查询在旧数据, 不在新数据中的值,  就是应该卖出的股票
  const name1 = _.map(prev_stocks, 'stock_name');
  const name2 = _.map(current_stocks, 'stock_name');
  const stock_names = _.uniq([...name1, ...name2]);

  const res: TStock[] = [];
  // 
  stock_names.map((stock_name, idx) => {

    const prev = prev_stocks.find(p => p.stock_name == stock_name);
    const current = current_stocks.find(c => c.stock_name == stock_name);
    if (prev && current) {
      //两边都有
      res.push({
        ...prev,
        sort: idx + 1
      })
    }
    // 上期没有这期有, 应该买入
    if (!prev && current) {
      res.push({
        ...current,
        sort: idx + 1,
        will_buy: true
      })
    }
    // 上期有这期无, 应该卖出
    if (prev && !current) {
      res.push({
        ...prev,
        sort: idx + 1,
        will_sell: true
      })
    }
  })

  return res;
}


const sendMail = (html: string) => {
  // 发件人信息
  const transporter = nodemailer.createTransport({
    host: 'smtp.163.com',
    secure: true,
    // 发件人邮箱和账号
    auth: {
      user: process.env.EMAIL_ACCOUNT,
      // 发件人邮箱的授权码,在邮箱中配置生成, 不是邮箱登录密码
      pass: process.env.EMAIL_PASS
    }
  })

  // 收件人信息
  const receiver = {
    from: `小市值robbot<${process.env.EMAIL_ACCOUNT}>`,
    // 主题
    subject: '小市值策略调仓计划',
    to: '1176948047@qq.com',
    html: html
  }
  // 发送邮件
  transporter.sendMail(receiver, (error, info) => {
    if (error) {
      return console.log("邮件发送过程中出错--", error);
    }
    transporter.close();
    console.log("发送成功---", info.response);
  })

}

const lastFriday = () => {
  const today = dayjs();
  let friday = today.day(5);
  const dayofWeek = today.day();
  // 如果今天不是周五, 那么最近的周五是上周五
  if (dayofWeek < 5) {
    friday = friday.subtract(1, 'week');
  }
  return friday;
}

const main = async () => {
  // const _currentDate = lastFriday();
  // const _lastDate = _currentDate.subtract(2, 'week');

  // const lastDate = _lastDate.format(DAY_FORMAT)
  // const currentDate = _currentDate.format(DAY_FORMAT)
  const currentDate = '2024-03-26'
  const lastDate = null
  // 两周前选股结果
  const last_res = await select_stock(lastDate);
  // 本周选股结果
  const current_res = await select_stock(currentDate);
  // 
  // const last_res:any[] = [];
  const data = await stockChanges(last_res, current_res);
  const template = fs.readFileSync(__dirname + '/template.ejs', 'utf-8');
  const html = ejs.render(template, { data: data,  currentDate, lastDate });
  // // // fs.writeFileSync(__dirname+'/aa.html', html, 'utf-8');
  sendMail(html);

}


main();